home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / src / mosmllib / Polyhash.sml < prev    next >
Encoding:
Text File  |  1997-08-18  |  8.2 KB  |  293 lines  |  [TEXT/R*ch]

  1. (* Modified for Moscow ML from SML/NJ Library version 0.2
  2.  *
  3.  * COPYRIGHT (c) 1992 by AT&T Bell Laboratories.
  4.  * See file mosml/copyrght/copyrght.att for details.
  5.  *
  6.  * Original author: John Reppy, AT&T Bell Laboratories, Murray Hill, NJ 07974
  7.  *)
  8.  
  9. datatype ('key, 'data) bucket_t
  10.   = NIL
  11.   | B of int * 'key * 'data * ('key, 'data) bucket_t
  12.  
  13. datatype ('key, 'data) hash_table = 
  14.     HT of {hashVal   : 'key -> int,
  15.        sameKey   : 'key * 'key -> bool,
  16.        not_found : exn,
  17.        table     : ('key, 'data) bucket_t Array.array ref,
  18.        n_items   : int ref}
  19.  
  20. local 
  21.     prim_val andb_      : int -> int -> int = 2 "and";
  22.     prim_val lshift_    : int -> int -> int = 2 "shift_left";
  23. in 
  24.     fun index (i, sz) = andb_ i (sz-1)
  25.  
  26.   (* find smallest power of 2 (>= 32) that is >= n *)
  27.     fun roundUp n = 
  28.     let fun f i = if (i >= n) then i else f (lshift_ i 1)
  29.     in f 32 end
  30. end;
  31.  
  32.   (* Create a new table; the int is a size hint and the exception
  33.    * is to be raised by find.
  34.    *)
  35.     fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{
  36.             hashVal=hashVal,
  37.         sameKey=sameKey,
  38.         not_found = notFound,
  39.         table = ref (Array.array(roundUp sizeHint, NIL)),
  40.         n_items = ref 0
  41.       };
  42.  
  43.   (* conditionally grow a table *)
  44.     fun growTable (HT{table, n_items, ...}) = let
  45.         val arr = !table
  46.         val sz = Array.length arr
  47.         in
  48.           if (!n_items >= sz)
  49.         then let
  50.           val newSz = sz+sz
  51.           val newArr = Array.array (newSz, NIL)
  52.           fun copy NIL = ()
  53.             | copy (B(h, key, v, rest)) = let
  54.             val indx = index (h, newSz)
  55.             in
  56.               Array.update (newArr, indx,
  57.                 B(h, key, v, Array.sub(newArr, indx)));
  58.               copy rest
  59.             end
  60.           fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1))
  61.           in
  62.             (bucket 0) handle _ => ();
  63.             table := newArr
  64.           end
  65.         else ()
  66.         end (* growTable *);
  67.  
  68.   (* Insert an item.  If the key already has an item associated with it,
  69.    * then the old item is discarded.
  70.    *)
  71.     fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
  72.     let
  73.       val arr = !table
  74.       val sz = Array.length arr
  75.       val hash = hashVal key
  76.       val indx = index (hash, sz)
  77.       fun look NIL = (
  78.         Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx)));
  79.         n_items := !n_items + 1;
  80.         growTable tbl;
  81.         NIL)
  82.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  83.         then B(hash, key, item, r)
  84.         else (case (look r)
  85.            of NIL => NIL
  86.             | rest => B(h, k, v, rest)
  87.           (* end case *))
  88.       in
  89.         case (look (Array.sub (arr, indx)))
  90.          of NIL => ()
  91.           | b => Array.update(arr, indx, b)
  92.       end;
  93.  
  94.   (* Insert an item if not there already; if it is there already, 
  95.      then return the old data value and leave the table unmodified..
  96.    *)
  97.     fun peekinsert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) =
  98.     let val arr = !table
  99.         val sz = Array.length arr
  100.         val hash = hashVal key
  101.         val indx = index (hash, sz)
  102.         fun look NIL = 
  103.         (Array.update(arr, indx, B(hash, key, item, 
  104.                        Array.sub(arr, indx)));
  105.          n_items := !n_items + 1;
  106.          growTable tbl;
  107.          NONE)
  108.           | look (B(h, k, v, r)) = 
  109.         if hash = h andalso sameKey(key, k) then SOME v
  110.         else look r
  111.     in
  112.         look (Array.sub (arr, indx))
  113.     end;
  114.  
  115.   (* find an item, the table's exception is raised if the item doesn't exist *)
  116.     fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let
  117.       val arr = !table
  118.       val sz = Array.length arr
  119.       val hash = hashVal key
  120.       val indx = index (hash, sz)
  121.       fun look NIL = raise not_found
  122.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  123.         then v
  124.         else look r
  125.       in
  126.         look (Array.sub (arr, indx))
  127.       end;
  128.  
  129.   (* look for an item, return NONE if the item doesn't exist *)
  130.     fun peek (HT{hashVal, sameKey, table, ...}) key = let
  131.       val arr = !table
  132.       val sz = Array.length arr
  133.       val hash = hashVal key
  134.       val indx = index (hash, sz)
  135.       fun look NIL = NONE
  136.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  137.         then SOME v
  138.         else look r
  139.       in
  140.         look (Array.sub (arr, indx))
  141.       end;
  142.  
  143.   (* Remove an item.  The table's exception is raised if
  144.    * the item doesn't exist.
  145.    *)
  146.     fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let
  147.       val arr = !table
  148.       val sz = Array.length arr
  149.       val hash = hashVal key
  150.       val indx = index (hash, sz)
  151.       fun look NIL = raise not_found
  152.         | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k))
  153.         then (v, r)
  154.         else let val (item, r') = look r in (item, B(h, k, v, r')) end
  155.       val (item, bucket) = look (Array.sub (arr, indx))
  156.       in
  157.         Array.update (arr, indx, bucket);
  158.         n_items := !n_items - 1;
  159.         item
  160.       end (* remove *);
  161.  
  162.   (* Return the number of items in the table *)
  163.    fun numItems (HT{n_items, ...}) = !n_items
  164.  
  165.   (* return a list of the items in the table *)
  166.     fun listItems (HT{table = ref arr, n_items, ...}) = let
  167.       fun f (_, l, 0) = l
  168.         | f (~1, l, _) = l
  169.         | f (i, l, n) = let
  170.         fun g (NIL, l, n) = f (i-1, l, n)
  171.           | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1)
  172.         in
  173.           g (Array.sub(arr, i), l, n)
  174.         end
  175.       in
  176.         f ((Array.length arr) - 1, [], !n_items)
  177.       end (* listItems *);
  178.  
  179.   (* Apply a function to the entries of the table *)
  180.     fun apply f (HT{table, ...}) = let
  181.       fun appF NIL = ()
  182.         | appF (B(_, key, item, rest)) = (
  183.         f (key, item);
  184.         appF rest)
  185.       val arr = !table
  186.       val sz = Array.length arr
  187.       fun appToTbl i = if (i < sz)
  188.         then (appF (Array.sub (arr, i)); appToTbl(i+1))
  189.         else ()
  190.       in
  191.         appToTbl 0
  192.       end (* apply *);
  193.  
  194.   (* Map a table to a new table that has the same keys and exception *)
  195.     fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let
  196.       fun mapF NIL = NIL
  197.         | mapF (B(hash, key, item, rest)) =
  198.         B(hash, key, f (key, item), mapF rest)
  199.       val arr = !table
  200.       val sz = Array.length arr
  201.       val newArr = Array.array (sz, NIL)
  202.       fun mapTbl i = if (i < sz)
  203.         then (
  204.           Array.update(newArr, i, mapF (Array.sub(arr, i)));
  205.           mapTbl (i+1))
  206.         else ()
  207.       in
  208.         mapTbl 0;
  209.         HT{hashVal=hashVal,
  210.            sameKey=sameKey,
  211.            table = ref newArr, 
  212.            n_items = ref(!n_items), 
  213.            not_found = not_found}
  214.       end (* transform *);
  215.  
  216.   (* remove any hash table items that do not satisfy the given
  217.    * predicate.
  218.    *)
  219.     fun filter pred (HT{table, n_items, not_found, ...}) = let
  220.       fun filterP NIL = NIL
  221.         | filterP (B(hash, key, item, rest)) = if (pred(key, item))
  222.         then B(hash, key, item, filterP rest)
  223.         else filterP rest
  224.       val arr = !table
  225.       val sz = Array.length arr
  226.       fun filterTbl i = if (i < sz)
  227.         then (
  228.           Array.update (arr, i, filterP (Array.sub (arr, i)));
  229.           filterTbl (i+1))
  230.         else ()
  231.       in
  232.         filterTbl 0
  233.       end (* filter *);
  234.  
  235.   (* Map a table to a new table that has the same keys, exception,
  236.      hash function, and equality function *)
  237.  
  238.     fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let
  239.       fun mapF NIL = NIL
  240.         | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest)
  241.       val arr = !table
  242.       val sz = Array.length arr
  243.       val newArr = Array.array (sz, NIL)
  244.       fun mapTbl i = if (i < sz)
  245.         then (
  246.           Array.update(newArr, i, mapF (Array.sub(arr, i)));
  247.           mapTbl (i+1))
  248.         else ()
  249.       in
  250.         mapTbl 0;
  251.         HT{hashVal=hashVal, 
  252.            sameKey=sameKey, 
  253.            table = ref newArr, 
  254.            n_items = ref(!n_items), 
  255.            not_found = not_found}
  256.       end (* transform *);
  257.  
  258.   (* Create a copy of a hash table *)
  259.     fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let
  260.       val arr = !table
  261.       val sz = Array.length arr
  262.       val newArr = Array.array (sz, NIL)
  263.       fun mapTbl i = (
  264.         Array.update (newArr, i, Array.sub(arr, i));
  265.         mapTbl (i+1))
  266.       in
  267.         (mapTbl 0) handle _ => ();
  268.         HT{hashVal=hashVal, 
  269.            sameKey=sameKey,
  270.            table = ref newArr, 
  271.            n_items = ref(!n_items), 
  272.            not_found = not_found}
  273.       end (* copy *);
  274.  
  275.   (* returns a list of the sizes of the various buckets.  This is to
  276.    * allow users to gauge the quality of their hashing function.
  277.    *)
  278.     fun bucketSizes (HT{table = ref arr, ...}) = let
  279.       fun len (NIL, n) = n
  280.         | len (B(_, _, _, r), n) = len(r, n+1)
  281.       fun f (~1, l) = l
  282.         | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l)
  283.       in
  284.         f ((Array.length arr)-1, [])
  285.       end
  286.  
  287. prim_val hash_param : int -> int -> 'a -> int = 3 "hash_univ_param";
  288.  
  289. fun hash x = hash_param 50 500 x;
  290.  
  291. fun mkPolyTable (sizeHint, notFound) = 
  292.      mkTable (hash, op=) (sizeHint, notFound);
  293.